package org.imixs.manik.webstat.jpa;

import java.util.Calendar;
import java.util.StringTokenizer;
import java.util.logging.Logger;

import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import nl.bitwalker.useragentutils.UserAgent;

/**
 * Access Log entry. The following entries from a access log will be stored:
 * <ul>
 * <li>host = remotehost
 * <li>username = remote user name
 * <li>date = request datetime
 * <li>request_uri = uri part from the request
 * <li>request_method = method part from the request (POST, GET, ...)
 * <li>bytes = size of response
 * <li>referer = referer URI
 * <li>useragent_browser = browser ident (Mozilla, Firefox,...)
 * <li>useragent_language = user language
 * 
 * 
 * 
 * The following entries will be ignored and not stored into the database (these
 * entries are marked as transient):
 * <ul>
 * <li>rfc931
 * <li>request
 * <li>useragent
 * 
 * 
 * We use Bitwalker to parse the useragent string
 * 
 * @see http://user-agent-utils.java.net/
 * 
 * @author rsoika
 * 
 */
@javax.persistence.Entity
public class AccessEntity implements java.io.Serializable {
	/**
	 * 
	 */

	private static Logger logger = Logger.getLogger("org.imixs.manik.webstat");

	private static final long serialVersionUID = 1L;
	private long id;
	private AccessLog accessLog;

	private String host;
	private String domain;
	private String topdomain;
	private String rfc931;
	private String username;
	private Calendar datetime;
	private byte dayofmonth;
	private byte month;
	private String request;
	private byte request_method;
	private String request_uri;
	private String statuscode;
	private String bytes;
	private String referrer;
	private String useragent;
	private String useragent_browser;
	private String useragent_browsertype;
	private String useragent_operatingsystem;

	// private String cookies;

	/**
	 * default constructor for JPA
	 */
	public AccessEntity() {
		super();
	}

	/**
	 * returns the unique identifier for the Entity.
	 * 
	 * @return universal id
	 */
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	public long getId() {
		return id;
	}

	protected void setId(long aID) {
		id = aID;
	}

	// we do not use : cascade = CascadeType.PERSIST
	// because of unidirectional relationship
	@ManyToOne(fetch = FetchType.LAZY)
	public AccessLog getAccessLog() {
		return accessLog;
	}

	public void setAccessLog(AccessLog accessLog) {
		this.accessLog = accessLog;
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public String getDomain() {
		return domain;
	}

	public void setDomain(String domain) {
		this.domain = domain;
	}

	public String getTopdomain() {
		return topdomain;
	}

	public void setTopdomain(String topdomain) {
		this.topdomain = topdomain;
	}

	@Transient
	public String getRfc931() {
		return rfc931;
	}

	public void setRfc931(String rfc931) {
		this.rfc931 = rfc931;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Temporal(TemporalType.TIMESTAMP)
	public Calendar getDatetime() {
		return datetime;
	}

	public void setDatetime(Calendar datetime) {
		this.datetime = datetime;
		
		// update dayofmonth
		if (datetime!=null)
			setDayofmonth((byte) datetime.get(Calendar.DAY_OF_MONTH));
		else
			setDayofmonth((byte)0);
		
		// update month
		if (datetime!=null)
			setMonth((byte) datetime.get(Calendar.MONTH));
		else
			setMonth((byte)0);
	}

	@Transient
	public String getRequest() {
		return request;
	}

	public byte getDayofmonth() {
		return dayofmonth;
	}

	public void setDayofmonth(byte dayofmonth) {
		this.dayofmonth = dayofmonth;
	}

	public byte getMonth() {
		return month;
	}

	public void setMonth(byte month) {
		this.month = month;
	}

	/**
	 * This method parses the request string and updates the properties
	 * request_method and request_uri
	 * 
	 * @param request
	 */
	public void setRequest(String request) {
		this.request = request;
		try {
			// split request into 3 parts
			StringTokenizer st = new StringTokenizer(request, " ");
			String sMethod = st.nextToken();
			String sURI = st.nextToken();

			// test sMethod
			if ("GET".equals(sMethod.toUpperCase()))
				setRequest_method((byte) 1);
			else if ("POST".equals(sMethod.toUpperCase()))
				setRequest_method((byte) 2);
			else if ("DELETE".equals(sMethod.toUpperCase()))
				setRequest_method((byte) 3);
			else
				setRequest_method((byte) 0);

			// set uri
			setRequest_uri(sURI);

		} catch (Exception e) {
			logger.warning("unable to parse request : " + request);
		}

	}

	public byte getRequest_method() {
		return request_method;
	}

	public void setRequest_method(byte request_method) {
		this.request_method = request_method;
	}

	public String getRequest_uri() {
		return request_uri;
	}

	public void setRequest_uri(String request_uri) {
		if (request_uri != null && request_uri.length() > 255)
			this.request_uri = request_uri.substring(0, 254);
		else
			this.request_uri = request_uri;
	}

	/**
	 * Request method : GET=1 POST=2 DELETE=3
	 * 
	 * @return
	 */

	public String getStatuscode() {
		return statuscode;
	}

	public void setStatuscode(String statuscode) {
		this.statuscode = statuscode;
	}

	public String getBytes() {
		return bytes;
	}

	public void setBytes(String bytes) {
		this.bytes = bytes;
	}

	public String getReferrer() {
		return referrer;
	}

	public void setReferrer(String referrer) {
		if (referrer != null && referrer.length() > 255)
			this.referrer = referrer.substring(0, 254);
		else
			this.referrer = referrer;
	}

	@Transient
	public String getUseragent() {
		return useragent;
	}

	public void setUseragent(String auseragent) {
		this.useragent = auseragent;
		if (useragent != null) {
			UserAgent userAgent = UserAgent.parseUserAgentString(useragent);
			if (userAgent != null) {
				setUseragent_browser(userAgent.getBrowser().getName());
				setUseragent_operatingsystem(userAgent.getOperatingSystem()
						.getName());
				setUseragent_browsertype(userAgent.getBrowser()
						.getBrowserType().getName());
			}
		}
	}

	public String getUseragent_browser() {
		return useragent_browser;
	}

	public void setUseragent_browser(String useragent_browser) {
		this.useragent_browser = useragent_browser;
	}

	public String getUseragent_operatingsystem() {
		return useragent_operatingsystem;
	}

	public void setUseragent_operatingsystem(String useragent_operatingsystem) {
		this.useragent_operatingsystem = useragent_operatingsystem;
	}

	public String getUseragent_browsertype() {
		return useragent_browsertype;
	}

	public void setUseragent_browsertype(String useragent_browsertype) {
		this.useragent_browsertype = useragent_browsertype;
	}

}
